import { urlEncodeValue } from "../helper.ts";
import { FieldParam, FieldTupleParam, Value } from "../main.ts";
import { Handler } from "./index.ts";

export class OpHandler implements Handler {
  process<T, Extra>(param: FieldParam<T, Extra>, group?: string): string {
    if (group) {
      return `${group}.${String(param.label)}-op=${param.op}` + "&" +
        `${group}.${String(param.label)}=${
          urlEncodeValue(param.value as Value)
        }`;
    }
    return `${String(param.label)}-op=${param.op}` +
      "&" + `${String(param.label)}=${urlEncodeValue(param.value as Value)}`;
  }

  check<T, Extra>(param: FieldParam<T, Extra>): void {
    if (param.value === undefined) {
      throw new Error(`${String(param.label)} is required`);
    }
    if (param.value instanceof Array) {
      throw new Error(`${String(param.op)} is not support array`);
    }
  }

  processTuple<T, Extra>(
    param: FieldTupleParam<T, Extra>,
    group?: string,
  ): string {
    if (group) {
      return `${group}.${String(param[0])}-op=${param[1]}` + "&" +
        `${group}.${String(param[0])}=${param[2]}`;
    }
    return `${String(param[0])}-op=${param[1]}` +
      "&" + `${String(param[0])}=${urlEncodeValue(param[2] as Value)}`;
  }

  checkTuple<T, Extra>(param: FieldTupleParam<T, Extra>): void {
    if (param[2] === undefined) {
      throw new Error(`${String(param[0])} is required`);
    }
    if (param[2] instanceof Array) {
      throw new Error(`${String(param[1])} is not support array`);
    }
  }

  processObj<T, Extra>(
    obj: object,
    param: FieldParam<T, Extra>,
    group?: string,
  ): void {
    if (group) {
      Object.assign(obj, {
        [`${group}.${param.label}-op`]: param.op,
        [`${group}.${param.label}`]: urlEncodeValue(param.value as Value),
      });
      return;
    }
    Object.assign(obj, {
      [`${param.label}-op`]: param.op,
      [`${param.label}`]: urlEncodeValue(param.value as Value),
    });
  }

  processObjTuple<T, Extra>(
    obj: object,
    param: FieldTupleParam<T, Extra>,
    group?: string,
  ): void {
    if (group) {
      Object.assign(obj, {
        [`${group}.${String(param[0])}-op`]: param[1],
        [`${group}.${String(param[0])}`]: param[2],
      });
      return;
    }

    Object.assign(obj, {
      [`${String(param[0])}-op`]: param[1],
      [`${String(param[0])}`]: urlEncodeValue(param[2] as Value),
    });
  }
}
